/*
 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2014年7月2日
 * <修改描述:>
 */
package com.tx.core.util;

import com.tx.core.exceptions.util.AssertUtils;

import java.lang.management.ManagementFactory;
import java.time.*;
import java.util.Date;

/**
 * 时间工具类<br/>
 * <功能详细描述>
 *
 * @author Administrator
 * @version [版本号, 2014年7月2日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class DateUtils {

    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static String[] COM_PARSE_PATTERNS = {"yyyy-MM-dd",
            "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd",
            "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd",
            "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /** 每天秒数 */
    //86400000
    public static long DAY_SECOND_COUNT = 1000 * 60 * 60 * 24;

    /** 基准日期对应的秒数,基于当前时区的1970年1月1日0时0分0秒0微秒为基准 */
    public static long BASE_DATE_TIME = asDate(
            LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0)).getTime();


    /**
     * 将LocalDate转换为Date
     * <功能详细描述>
     *
     * @param localDate
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date asDate(LocalDate localDate) {
        AssertUtils.notNull(localDate, "localDate is null.");

        return Date.from(localDate.atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant());
    }

    /**
     * 将localDateTime转换为Date
     * <功能详细描述>
     *
     * @param localDate
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date toDate(LocalDate localDate) {
        AssertUtils.notNull(localDate, "localDate is null.");

        return Date.from(localDate.atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant());
    }

    /**
     * 将LocalDateTime转换为Date
     * <功能详细描述>
     *
     * @param localDateTime
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date asDate(LocalDateTime localDateTime) {
        AssertUtils.notNull(localDateTime, "localDateTime is null.");

        return Date
                .from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 将localDateTime转换为Date
     * <功能详细描述>
     *
     * @param localDateTime
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date toDate(LocalDateTime localDateTime) {
        AssertUtils.notNull(localDateTime, "localDateTime is null.");

        return Date
                .from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 将Date转换为LocalDate
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return LocalDate [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static LocalDate asLocalDate(Date date) {
        AssertUtils.notNull(date, "date is null.");

        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    /**
     * 将Date转换为LocalDate
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return LocalDate [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static LocalDate toLocalDate(Date date) {
        AssertUtils.notNull(date, "date is null.");

        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    /**
     * 将Date转换为LocalDateTime
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return LocalDateTime [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static LocalDateTime asLocalDateTime(Date date) {
        AssertUtils.notNull(date, "date is null.");

        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    /**
     * 将Date转换为LocalDateTime
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return LocalDateTime [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        AssertUtils.notNull(date, "date is null.");

        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    /**
     * 根据生日计算当前年龄<br/>
     * <功能详细描述>
     *
     * @param birthday
     * @return [参数说明]
     * @return int [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static int getAge(Date birthday) {
        AssertUtils.notNull(birthday, "birthday is null");

        LocalDateTime birthdayDateTime = asLocalDateTime(birthday);
        LocalDateTime now = LocalDateTime.now();

        int age = 0;
        if (now.compareTo(birthdayDateTime) < 0) {
            age = 0;
        } else if (now.getMonthValue() < birthdayDateTime.getMonthValue()
                || now.getDayOfMonth() < birthdayDateTime.getDayOfMonth()) {
            age = now.getYear() - birthdayDateTime.getYear();
            age = age <= 0 ? 0 : age - 1;
        } else {
            age = now.getYear() - birthdayDateTime.getYear();
        }
        return age;
    }

    /**
     * 获取对应时间对应标准时间间隔天数
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return int [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static int getDays(Date date) {
        AssertUtils.notNull(date, "date is null");

        long res = (asDate(asLocalDate(date)).getTime() - BASE_DATE_TIME)
                / DAY_SECOND_COUNT;
        return (int) res;
    }

    /**
     * 获取两个时间之间最大的时间<br/>
     * <功能详细描述>
     *
     * @param afterDate
     * @param preDate
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date max(Date afterDate, Date preDate) {
        if (afterDate == null) {
            return preDate;
        }
        if (preDate == null) {
            return afterDate;
        }
        if (afterDate.compareTo(preDate) > 0) {
            return afterDate;
        } else {
            return preDate;
        }
    }

    //    /**
    //     * 比较两个日期
    //     *     如果两者为同天则返回0
    //     *     如果前大于后，则 > 0
    //     *     反之 < 0
    //     *<功能详细描述>
    //     * @param preDate
    //     * @param afterDate
    //     * @return [参数说明]
    //     * 
    //     * @return int [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static int compareByDay(Date afterDate, Date preDate) {
    //        return calculateNumberOfDaysBetween(afterDate, preDate);
    //    }

    //    /**
    //     * 计算两个日期之间间隔天数<br/>
    //     *     如果为同一天，则返回0，如果>0则后日期大于前日期，<0则后日期小于前日期<br/>
    //     *<功能详细描述>
    //     * @param preDate
    //     * @param afterDate
    //     * @return [参数说明]
    //     * 
    //     * @return int [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static int calculateNumberOfDaysBetween(Date afterDate,
    //            Date preDate) {
    //        if (org.apache.commons.lang3.time.DateUtils.isSameDay(afterDate,
    //                preDate)) {
    //            return 0;
    //        }
    //        int afterDays = getDays(afterDate);
    //        int preDays = getDays(preDate);
    //        return afterDays - preDays;
    //    }

    /**
     * 将localDateTime转换为Date
     * <功能详细描述>
     *
     * @param date
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date add(Date date, Duration duration) {
        AssertUtils.notNull(date, "date is null.");
        AssertUtils.notNull(duration, "duration is null.");

        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime datetime = asLocalDateTime(date).plus(duration);

        Date res = Date.from(datetime.atZone(zoneId).toInstant());
        return res;
    }

    /**
     * 获取服务器启动时间<br/>
     * <功能详细描述>
     *
     * @return [参数说明]
     * @return Date [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    public static void main(String[] args) {
        //getDays
        System.out.println(getDays(asDate(LocalDateTime.now())));

        System.out.println(
                (asDate(LocalDateTime.of(1970, 1, 1, 0, 0, 0))).getTime());

        System.out.println(getDays(new Date()));

        System.out.println(getDays(asDate(LocalDateTime.of(1970, 1, 2, 1, 0, 0))));
    }
}
